package com.wang.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wangq on 2021/7/11.
 *
 * 工厂类：使用反射技术生产对象
 */
public class BeanFactory {
    private static Map<String, Object> beanMap = new HashMap<>();

    // 读取解析XML
    static {
        System.out.println(">>>>>解析XML Bean工厂开始执行");
        // 读取配置文件
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans\\Beans.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            // 获取配置文件中所有bean元素节点
            List<Element> beanElementList = rootElement.selectNodes("//bean");
            for (Element beanElement : beanElementList) {
                // 获取到每个bean元素的id和class
                String id = beanElement.attributeValue("id");
                String clazz = beanElement.attributeValue("class");
                //通过反射技术实例化对象的类
                Class<?> aClass = Class.forName(clazz);
                //  实例化对象
                Object instance = aClass.newInstance();

                beanMap.put(id, instance);
            }

            // 实例化完成后，把实例化对象中需要依赖的对象，也都实例化，并赋值给当前对象
            // 获取所有对象的依赖关系 即property元素中配置的对象，通过反射赋值给其父节点
            List<Element> propertyElementList = rootElement.selectNodes("//property");
            for (Element propertyElement : propertyElementList) {
                String name = propertyElement.attributeValue("name"); // set方法名去掉set
                String bean = propertyElement.attributeValue("bean"); // 实例化的接口
                String ref = propertyElement.attributeValue("ref"); // 实例化接口的实现类对象

                // 获取父对象节点id
                Element parentElement = propertyElement.getParent();
                String parentId = parentElement.attributeValue("id");
                // 通过id获取父对象
                Object parentObject = beanMap.get(parentId);
                // 通过反射获取父对象中给依赖对象赋值的方法
                Method[] methods = parentObject.getClass().getMethods();
                for (Method method : methods) {
                    if (method.getName().equalsIgnoreCase("set" + name)) {
                        method.invoke(parentObject, beanMap.get(ref));
                    }
                }
//                Method method = parentObject.getClass().getMethod("set" + name, Class.forName(bean));
//                method.invoke(parentObject, beanMap.get(ref));
                // 刷新赋值后的对象
                beanMap.put(parentId, parentObject);
            }
        } catch (DocumentException | ClassNotFoundException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }


    // 提供获根据beanId取实例化对象的接口
    public static Object getBeanInstance(String beanId) {
        return beanMap.get(beanId);
    }
}
